资源
课程 An Introduction to Scripting
将视图改成如下图所示,拖动视图的右上角可以分离视图:
编写 python 代码:
import bpyclass TestPanel (bpy.types.Panel): bl_label = "Test Panel" bl_idname = "PT_TestPanel" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'My 1st Addona' def draw (self, context ): layout = self.layout row = layout.row() row.label(text='Add an object' , icon='CUBE' ) row = layout.row() row.operator('mesh.primitive_cube_add' , icon='CUBE' ) row.operator('mesh.primitive_uv_sphere_add' , icon='SPHERE' ) row = layout.row() row.operator('object.text_add' , icon='FILE_FONT' ) def register (): bpy.utils.register_class(TestPanel) def unregister (): bpy.utils.unsregister_class(TestPanel) if __name__ == '__main__' : register()
这段python代码是在Blender中添加一个面板(Panel),面板的名称为“Test Panel”,在3D视窗中显示,属于UI面板类型,属于"My 1st Addona"类别。这个面板里面添加了三个按钮,分别为添加一个立方体、添加一个球体、添加一个文字。
具体解释如下:
第一行导入了blender的Python API,可以让我们在Python中使用Blender的功能。
接下来定义了一个名为TestPanel的类,该类继承自bpy.types.Panel,用于创建面板。bl_label表示显示的名称,bl_idname是给面板加上一个独有的ID,可以在其他地方调用它,bl_space_type表示要显示在哪种编辑器空间中,这里是VIEW_3D
3D视窗中显示,bl_region_type表示要显示在哪个区域内,这里是'UI' 用户界面标签页。bl_category表示在哪个类别下进行分组,这里将其放在“My 1st Addona”。
然后是draw函数,用于绘制面板上的组件。self.layout是布局对象,代表整个面板的布局。通过layout对象的row()函数,可以创建一行组件。在这个例子中,首先创建一行label文本,然后又创建两个button,分别调用了mesh.primitive_cube_add
添加立方体,mesh.primitive_uv_sphere_add
添加球体,最后再创建一个添加文字的按钮。
register()函数使用bpy.utils.register_class()
方法将TestPanel类注册到Blender中,使其可用。
unregister()函数使用bpy.utils.unregister_class()
方法取消注册TestPanel类。
最后检查脚本是否在Blender内运行,如果是,则执行register()函数。
在 3D Viewport
视图下按 n
可以打开面板。
面板的图标名称可以通过Edit
-Preferences
-Add-ons
-搜索icon
-Icon Viewer
的方式找到:
带创建物体的英文名称可以通过下图方式找到:
Finishing the Object Adder Add-on 继续完善之前写的插件:
bl_info = { 'name' : 'Object Adder' , 'author' : 'Darkfall' , 'version' : (1 , 0 ), 'blender' : (3 , 51 , 0 ), 'location' : 'View3d > Tool' , 'warning' : '' , 'wiki_url' : '' , 'category' : 'Add Mesh' , }import bpyclass TestPanel (bpy.types.Panel): bl_label = "Test Panel" bl_idname = "PT_TestPanel" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'My 1st Addona' def draw (self, context ): layout = self.layout layout.scale_y = 1.4 row = layout.row() row.label(text='Add an object' , icon='OBJECT_ORIGIN' ) row = layout.row() row.operator('mesh.primitive_cube_add' , icon='CUBE' ) row.operator('mesh.primitive_uv_sphere_add' , icon='SPHERE' ) row = layout.row() row.operator('object.text_add' , icon='FILE_FONT' ) class PanelA (bpy.types.Panel): bl_label = "Scale" bl_idname = "PT_PanelA" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'My 1st Addona' bl_parent_id = 'PT_TestPanel' bl_options = {'DEFAULT_CLOSED' } def draw (self, context ): layout = self.layout obj = context.object row = layout.row() row.label(text='Select an option to scale your object.' , icon='FONT_DATA' ) row = layout.row() row.operator('transform.resize' ) row = layout.row() layout.scale_y = 1.2 col = layout.column() col.prop(obj, 'scale' ) class PanelB (bpy.types.Panel): bl_label = "Specials" bl_idname = "PT_PanelB" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'My 1st Addona' bl_parent_id = 'PT_TestPanel' bl_options = {'DEFAULT_CLOSED' } def draw (self, context ): layout = self.layout row = layout.row() row.label(text='Select a Special Option' , icon='COLOR_BLUE' ) row = layout.row() row.operator('object.shade_smooth' , icon='MOD_SMOOTH' , text='Set Smooth Shading' ) row.operator('object.subdivision_set' ) row = layout.row() row.operator('object.modifier_add' )def register (): bpy.utils.register_class(TestPanel) bpy.utils.register_class(PanelA) bpy.utils.register_class(PanelB) def unregister (): bpy.utils.unsregister_class(TestPanel) bpy.utils.unregister_class(PanelA) bpy.utils.register_class(PanelB) if __name__ == '__main__' : register()
也可以通过 Edit
-Preferences
-Install...
的方式安装其他人写好的插件:
Preview: The Shader Library Add-on (Python Tutorial Result) How to create an Addon (The Shader Library) 教你怎么用 Python 写一个 Shader 插件:
调整窗口布局,一个 Shader Editor,一个 3D Viewport,一个 Text Editor:
这段代码定义了一个名为"Shader Libraey"的Blender插件,该插件提供了一个名为"Diamond"的着色器,可以在3D视图的工具栏中的"Shader Library"选项卡中访问。当用户点击该选项卡时,将显示一个面板,其中包含一个"选择要添加的着色器"标签和一个"Diamond"按钮,当用户单击该按钮时,将创建一个着色器并应用于活动对象上。
具体而言,该代码文件首先定义了包含插件名称、作者、版本等信息的字典。接下来定义了一个面板类ShaderMainPanel,它作为面板的主要控件,用于渲染用户界面。该面板包含一个文本标签和一个名为"shader.diamond_operator"的操作器,后者定义了所需的Diamond着色器。在操作器的execute()函数中,创建一个新材质,激活其节点编辑模式,删除默认的Principled BSDF节点,然后创建和连接多个颜色为红、绿、蓝的玻璃节点,最后创建混合节点和连接多个节点以生成最终的Diamond着色器,将其分配给当前活动对象。
最后,定义了两个函数register()和unregister(),它们用于在Blender应用程序中注册和取消注册插件的类。
bl_info = { 'name' : 'Shader Libraey' , 'author' : 'Darkfall' , 'version' : (1 , 0 ), 'blender' : (3 , 51 , 0 ), 'location' : 'View3d > Tool' , 'warning' : '' , 'wiki_url' : '' , 'category' : 'Add Shader' , }import bpyclass ShaderMainPanel (bpy.types.Panel): bl_label = "Shader Library" bl_idname = "SHADER_PT_MAINPANEL" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = "Shader Library" def draw (self, context ): layout = self.layout row = layout.row() row.label(text='Select a Shader to be added.' ) row.operator('shader.diamond_operator' )class SHADER_OT_DIAMOND (bpy.types.Operator): bl_label = "Diamond" bl_idname = "shader.diamond_operator" def execute (self, context ): material_diamond = bpy.data.materials.new(name="Diamond" ) material_diamond.use_nodes = True material_diamond.node_tree.nodes.remove(material_diamond.node_tree.nodes.get('Principled BSDF' )) material_output = material_diamond.node_tree.nodes.get('Material Output' ) material_output.location = (-400 ,0 ) glass1_node = material_diamond.node_tree.nodes.new('ShaderNodeBsdfGlass' ) glass1_node.location = (-600 ,0 ) glass1_node.inputs[0 ].default_value = (1 , 0 , 0 , 1 ) glass1_node.inputs[2 ].default_value = 1.446 glass2_node = material_diamond.node_tree.nodes.new('ShaderNodeBsdfGlass' ) glass2_node.location = (-600 , -150 ) glass2_node.inputs[0 ].default_value = (0 , 1 , 0 , 1 ) glass2_node.inputs[2 ].default_value = 1.450 glass3_node = material_diamond.node_tree.nodes.new('ShaderNodeBsdfGlass' ) glass3_node.location = (-600 , -300 ) glass3_node.inputs[0 ].default_value = (0 , 0 , 1 , 1 ) glass3_node.inputs[2 ].default_value = 1.450 add1_node = material_diamond.node_tree.nodes.new('ShaderNodeAddShader' ) add1_node.location = (-400 ,-50 ) add1_node.label = "Add 1" add1_node.hide = True add1_node.select = False add2_node = material_diamond.node_tree.nodes.new('ShaderNodeAddShader' ) add2_node.location = (0 ,0 ) add2_node.label = "Add 2" add2_node.hide = True add2_node.select = False glass4_node = material_diamond.node_tree.nodes.new('ShaderNodeBsdfGlass' ) glass4_node.location = (-150 , -150 ) glass4_node.inputs[0 ].default_value = (1 , 1 , 1 , 1 ) glass4_node.inputs[2 ].default_value = 1.450 glass4_node.select = False mix1_node = material_diamond.node_tree.nodes.new('ShaderNodeMixShader' ) mix1_node.location = (200 ,0 ) mix1_node.select = False material_diamond.node_tree.links.new(glass1_node.outputs[0 ], add1_node.inputs[0 ]) material_diamond.node_tree.links.new(glass2_node.outputs[0 ], add1_node.inputs[1 ]) material_diamond.node_tree.links.new(add1_node.outputs[0 ], add2_node.inputs[0 ]) material_diamond.node_tree.links.new(glass3_node.outputs[0 ], add2_node.inputs[1 ]) material_diamond.node_tree.links.new(add2_node.outputs[0 ], mix1_node.inputs[1 ]) material_diamond.node_tree.links.new(glass4_node.outputs[0 ], mix1_node.inputs[2 ]) material_diamond.node_tree.links.new(mix1_node.outputs[0 ], material_output.inputs[0 ]) bpy.context.object .active_material = material_diamond return {'FINISHED' }def register (): bpy.utils.register_class(ShaderMainPanel) bpy.utils.register_class(SHADER_OT_DIAMOND) def unregister (): bpy.utils.unregister_class(ShaderMainPanel) bpy.utils.unregister_class(SHADER_OT_DIAMOND) if __name__ == '__main__' : register()
Edit
-Preferences
-Add-ons
-搜索extra
-Add Mesh: Extra Objects
,这样 Blender 中就可以创建钻石形状的物体。
创建一个钻石形状的物体,运行代码,点击 Diamond
,就给该物体添加了一个 Shader:
可以从 Darkfall : Blender Python Tutorial: How to create an Add-on - The Shader Library [bpy] (darkfallblender.blogspot.com) 中的 ShaderLibrary.py - Google Drive 下载作者写的更复杂的 ShaderLibrary.py
。
Add a keyframe & Modifier with Python [learn python for beginners]
这段代码定义了一个名为"Hello World Panel"的Blender插件,该插件提供了一个名为"Neon"的着色器,可以在3D视图的工具栏中的"Name your New Tab"选项卡中访问。当用户点击该选项卡时,将显示一个面板,其中包含一个"Add Neon Shader"按钮,当用户单击该按钮时,将创建一个着色器并应用于活动对象上。
具体而言,该代码文件首先定义了一个名为HelloWorldPanel的面板类,该类作为面板的主要控件,用于渲染用户界面。该面板包含一个按钮,名为"shader.neon_operator"。在操作器的execute()函数中,创建一个新材质,激活其节点编辑模式,删除默认的Principled BSDF节点,然后创建和连接多个颜色为蓝色、灰色的玻璃节点,最后创建混合节点和连接多个节点以生成最终的Neon着色器,将其分配给当前活动对象。
最后,定义了两个函数register()和unregister(),它们用于在Blender应用程序中注册和取消注册插件的类。
import bpyclass HelloWorldPanel (bpy.types.Panel): """Creates a Panel in the Object properties window""" bl_label = "Hello World Panel" bl_idname = "OBJECT_PT_hello" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = "Name your New Tab" def draw (self, context ): layout = self.layout obj = context.object row = layout.row() row.operator('shader.neon_operator' ) class SHADER_OT_NEON (bpy.types.Operator): bl_label = 'Add Neon Shader' bl_idname = 'shader.neon_operator' def execute (self, context ): cur_frame = bpy.context.scene.frame_current material_neon = bpy.data.materials.new(name= "Neon" ) material_neon.use_nodes = True tree = material_neon.node_tree material_neon.node_tree.nodes.remove(material_neon.node_tree.nodes.get('Principled BSDF' )) material_output = material_neon.node_tree.nodes.get('Material Output' ) material_output.location = (400 ,0 ) emiss_node = material_neon.node_tree.nodes.new('ShaderNodeEmission' ) emiss_node.location = (200 ,0 ) emiss_node.inputs[0 ].default_value = (0.59 , 0.76 , 1 , 1 ) emiss_node.inputs[1 ].default_value = 2 emiss_node.inputs[1 ].keyframe_insert('default_value' , frame=cur_frame) data_path = f'nodes["{emiss_node.name} "].inputs[1].default_value' fcurves = tree.animation_data.action.fcurves fc = fcurves.find(data_path) if fc: new_mod = fc.modifiers.new('NOISE' ) new_mod.strength = 10 new_mod.depth = 1 material_neon.node_tree.links.new(emiss_node.outputs[0 ], material_output.inputs[0 ]) return {'FINISHED' }def register (): bpy.utils.register_class(HelloWorldPanel) bpy.utils.register_class(SHADER_OT_NEON)def unregister (): bpy.utils.unregister_class(HelloWorldPanel) bpy.utils.unregister_class(SHADER_OT_NEON)if __name__ == "__main__" : register()
创建了一个 shader 和一个 modifiers,使得绑定的物体一闪一闪的。
定义了一个 WM_OT_myOp
类,提供了一个 dialog box 提示,原视频的 Blender 版本有点旧,替换了一些代码:
class WM_OT_myOp (bpy.types.Operator): """Open the Add Cube Dialog Box""" bl_label = 'Add Cube Dialog Box' bl_idname = 'wm.myop' text: bpy.props.StringProperty(name='Enter Text' , default='' ) scale: bpy.props.FloatVectorProperty(name='Scale' , default=(1 , 1 , 1 )) def execute (self, context ): t = self.text s = self.scale bpy.ops.mesh.primitive_cube_add() obj = bpy.context.object obj.name = t obj.scale[0 ] = s[0 ] obj.scale[1 ] = s[1 ] obj.scale[2 ] = s[2 ] return {'FINISHED' } def invoke (self, context, event ): return context.window_manager.invoke_props_dialog(self)
整合到之前的 AddObjectScript.py
中,代码 row.operator('wm.myop', icon='CUBE', text='Cube')
将创建的 bl_idname = 'wm.myop'
的 WM_OT_myOp
加入到 TestPanel 中:
bl_info = { 'name' : 'Object Adder' , 'author' : 'Darkfall' , 'version' : (1 , 0 ), 'blender' : (3 , 51 , 0 ), 'location' : 'View3d > Tool' , 'warning' : '' , 'wiki_url' : '' , 'category' : 'Add Mesh' , }import bpyclass TestPanel (bpy.types.Panel): bl_label = "Test Panel" bl_idname = "PT_TestPanel" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'My 1st Addona' def draw (self, context ): layout = self.layout layout.scale_y = 1.4 row = layout.row() row.label(text='Add an object' , icon='OBJECT_ORIGIN' ) row = layout.row() row.operator('wm.myop' , icon='CUBE' , text='Cube' ) row = layout.row() row.operator('mesh.primitive_cube_add' , icon='CUBE' ) row.operator('mesh.primitive_uv_sphere_add' , icon='SPHERE' ) row = layout.row() row.operator('object.text_add' , icon='FILE_FONT' ) class PanelA (bpy.types.Panel): bl_label = "Scale" bl_idname = "PT_PanelA" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'My 1st Addona' bl_parent_id = 'PT_TestPanel' bl_options = {'DEFAULT_CLOSED' } def draw (self, context ): layout = self.layout obj = context.object row = layout.row() row.label(text='Select an option to scale your object.' , icon='FONT_DATA' ) row = layout.row() row.operator('transform.resize' ) row = layout.row() layout.scale_y = 1.2 col = layout.column() col.prop(obj, 'scale' ) class PanelB (bpy.types.Panel): bl_label = "Specials" bl_idname = "PT_PanelB" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'My 1st Addona' bl_parent_id = 'PT_TestPanel' bl_options = {'DEFAULT_CLOSED' } def draw (self, context ): layout = self.layout row = layout.row() row.label(text='Select a Special Option' , icon='COLOR_BLUE' ) row = layout.row() row.operator('object.shade_smooth' , icon='MOD_SMOOTH' , text='Set Smooth Shading' ) row.operator('object.subdivision_set' ) row = layout.row() row.operator('object.modifier_add' ) class WM_OT_myOp (bpy.types.Operator): """Open the Add Cube Dialog Box""" bl_label = 'Add Cube Dialog Box' bl_idname = 'wm.myop' text: bpy.props.StringProperty(name='Enter Text' , default='' ) scale: bpy.props.FloatVectorProperty(name='Scale' , default=(1 , 1 , 1 )) def execute (self, context ): t = self.text s = self.scale bpy.ops.mesh.primitive_cube_add() obj = bpy.context.object obj.name = t obj.scale[0 ] = s[0 ] obj.scale[1 ] = s[1 ] obj.scale[2 ] = s[2 ] return {'FINISHED' } def invoke (self, context, event ): return context.window_manager.invoke_props_dialog(self)def register (): bpy.utils.register_class(TestPanel) bpy.utils.register_class(PanelA) bpy.utils.register_class(PanelB) bpy.utils.register_class(WM_OT_myOp) def unregister (): bpy.utils.unsregister_class(TestPanel) bpy.utils.unregister_class(PanelA) bpy.utils.register_class(PanelB) bpy.utils.unregister_class(WM_OT_myOp) if __name__ == '__main__' : register()
开跑!点击 OK 就会创建一个相应名称和 Scale 的立方体。
Creating the Text Tool Add-on
这是一个简单的 Blender 插件,提供了一个 "Text Tool" 面板,用于添加文本对象。插件为用户提供了一些选项,如文本内容、比例尺度、是否居中编辑原点、是否挤压等。
在代码的开头,bl_info
字典定义了插件的基本信息,包括名称、作者、版本、Blender 版本要求、描述等等。这些信息将会在 Blender 中进行显示和识别。
OBJECT_PT_TextTool
类定义了插件的 UI 面板,在 View3D 视图中的 "Add" 菜单下可以找到它。面板中有一个按钮,用于调用 WM_OT_textOp
操作器类,添加指定的文本对象。
WM_OT_textOp
操作器类定义了添加文本对象的过程,并通过执行 execute()
方法在场景中添加文本对象。使用 invoke()
方法显示属性对话框,以便用户可以设置文本对象的属性。
在代码的末尾,register()
方法用于注册插件的类,unregister()
方法用于注销这些类。这使得 Blender 工具栏能够正确地显示插件,并在需要时供用户使用。
bl_info = { "name" : "Text Tool" , "author" : "Darkfall" , "version" : (1 , 0 ), "blender" : (3 , 51 , 0 ), "location" : "View3D > Add > Mesh > New Object" , "description" : "Adds a new Mesh Object" , "warning" : "" , "doc_url" : "" , "category" : "Add Mesh" , }import bpyclass OBJECT_PT_TextTool (bpy.types.Panel): """Creates a Panel in the Object properties window""" bl_label = "Text Tool" bl_idname = "OBJECT_PT_TextTool" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'Text Tool' def draw (self, context ): layout = self.layout row = layout.row() row.operator('wm.textop' , text='Add Text' , icon='OUTLINER_OB_FONT' ) class WM_OT_textOp (bpy.types.Operator): bl_label = 'Text Tool Operator' bl_idname = 'wm.textop' text: bpy.props.StringProperty(name='Enter Text' , default='' ) scale: bpy.props.FloatVectorProperty(name='Scale' , default=(1 , 1 , 1 )) center: bpy.props.BoolProperty(name='Center Origin' , default=False ) extrude: bpy.props.BoolProperty(name='Extrude' , default=False ) extrude_amount: bpy.props.FloatProperty(name='Extrude Amount' , default=0.06 ) def execute (self, context ): t = self.text s = self.scale c = self.center e = self.extrude ea = self.extrude_amount bpy.ops.object .text_add(enter_editmode=True , location=(0 , 0 , 0 )) bpy.ops.font.delete(type ='PREVIOUS_WORD' ) bpy.ops.font.text_insert(text=t) bpy.ops.object .editmode_toggle() if e == True : bpy.context.object .data.extrude = ea if c == True : bpy.context.object .data.align_x = 'CENTER' bpy.context.object .data.align_y = 'CENTER' return {'FINISHED' } def invoke (self, context, event ): return context.window_manager.invoke_props_dialog(self)def register (): bpy.utils.register_class(OBJECT_PT_TextTool) bpy.utils.register_class(WM_OT_textOp)def unregister (): bpy.utils.unregister_class(OBJECT_PT_TextTool) bpy.utils.register_class(WM_OT_textOp)if __name__ == "__main__" : register()
这将创建一个文字,是否居中和具有高度都是可选的。
Create Custom Node Group
Blender 的节点组是将多个节点整合在一起,以便于在不同的场景中重复使用。通过创建自定义节点组,用户可以自定义一组节点,然后在需要时将它们重复使用,而无需每次都手动连接一堆节点。
节点组可以包含多个输入和输出,这使得节点的使用更加灵活。例如,可以将某个算法封装在一个自定义节点组中,然后将其作为子程序一样反复使用,从而使整个工作流程更加高效。
除此之外,节点组还可以将多个节点封装在一起,隐藏内部的复杂性,从而简化整个项目的结构和管理。如果想要共享或者将你的节点组应用到其他项目中,你可以将它们保存为 .blend 文件或者 Python 脚本。
总之,节点组是 Blender 中非常实用的功能之一,它可以帮助用户提高工作效率,并简化项目管理流程,同时也使 Blender 更加强大和灵活。
这段代码是一个 Blender 插件,用于创建自定义节点组。
首先,代码定义了一个 NODE_PT_MAINPANEL
类,继承自 bpy.types.Panel
类,表示一个面板面板,包含在节点编辑器(NODE_EDITOR
)中的 UI 区域(UI
),并将其放在「New Tab」分类下。bl_label
设置面板名称为「Custom Node Group」,bl_idname
表示唯一 ID,用于在代码中引用该面板。
create_test_group()
函数用于创建节点组。它接收三个参数:context
对象、operator
对象和 group_name
字符串。此函数使用 bpy.data.node_groups.new()
创建一个新的节点组对象,并设置其类型为 'CompositorNodeTree'
,意味着创建一个合成节点树。接下来,该函数创建输入和输出节点,以及两个中间节点,并将它们连接起来。最后,该函数返回新创建的节点组对象。
NODE_OT_TEST
类继承自 bpy.types.Operator
类,代表一个操作员。bl_label
表示该操作员的名称,bl_idname
表示唯一 ID,用于在代码中引用该操作员。execute()
方法在执行该操作员时被调用,可以看到该方法调用 create_test_group()
函数创建自定义节点组,并将其添加到场景中。
最后,register()
和 unregister()
函数分别用于注册和注销 Blender 插件。register_class()
和 unregister_class()
方法被用于添加和移除定义的面板(NODE_PT_MAINPANEL
)和操作员(NODE_OT_TEST
),使它们在 Blender 中可用。if __name__ == "__main__":
代码块用于直接运行该脚本。这个代码块中的 register()
方法将插件注册到 Blender 中,使它可以在运行时使用。
import bpy class NODE_PT_MAINPANEL (bpy.types.Panel): bl_label = "Custom Node Group" bl_idname = "NODE_PT_MAINPANEL" bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' bl_category = 'New Tab' def draw (self, context ): layout = self.layout row = layout.row() row.operator('node.test_operator' ) def create_test_group (context, operator, group_name ): bpy.context.scene.use_nodes = True test_group = bpy.data.node_groups.new(group_name, 'CompositorNodeTree' ) group_in = test_group.nodes.new('NodeGroupInput' ) group_in.location = (-200 ,0 ) test_group.inputs.new('NodeSocketFloat' ,'Factor Value' ) test_group.inputs.new('NodeSocketColor' ,'Color Input' ) group_out = test_group.nodes.new('NodeGroupOutput' ) group_out.location = (400 ,0 ) test_group.outputs.new('NodeSocketColor' ,'Output' ) mask_node = test_group.nodes.new(type = 'CompositorNodeBoxMask' ) mask_node.location = (0 ,0 ) mask_node.rotation = 1 mix_node = test_group.nodes.new(type = 'CompositorNodeMixRGB' ) mix_node.location = (200 ,0 ) mix_node.use_clamp = True mix_node.blend_type = 'OVERLAY' link = test_group.links.new link(mask_node.outputs[0 ], mix_node.inputs[1 ]) link(group_in.outputs[0 ], mix_node.inputs[0 ]) link(group_in.outputs[1 ], mix_node.inputs[2 ]) link(mix_node.outputs[0 ], group_out.inputs[0 ]) return test_group class NODE_OT_TEST (bpy.types.Operator): bl_label = "Add Custom Node Group" bl_idname = "node.test_operator" def execute (self, context ): custom_node_name = "Test Node" my_group = create_test_group(self, context, custom_node_name) test_node = context.scene.node_tree.nodes.new('CompositorNodeGroup' ) test_node.node_tree = bpy.data.node_groups[my_group.name] test_node.use_custom_color = True test_node.color = (0.5 , 0.4 , 0.3 ) return {'FINISHED' } def register (): bpy.utils.register_class(NODE_PT_MAINPANEL) bpy.utils.register_class(NODE_OT_TEST) def unregister (): bpy.utils.unregister_class(NODE_PT_MAINPANEL) bpy.utils.unregister_class(NODE_OT_TEST) if __name__ == "__main__" : register()
Custom Drawing / Layout Improvements 美化了之前 TextTool.py
的界面:
bl_info = { "name" : "Text Tool" , "author" : "Darkfall" , "version" : (1 , 0 ), "blender" : (3 , 51 , 0 ), "location" : "View3D > Add > Mesh > New Object" , "description" : "Adds a new Mesh Object" , "warning" : "" , "doc_url" : "" , "category" : "Add Mesh" , }import bpyclass OBJECT_PT_TextTool (bpy.types.Panel): """Creates a Panel in the Object properties window""" bl_label = "Text Tool" bl_idname = "OBJECT_PT_TextTool" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'Text Tool' def draw (self, context ): layout = self.layout row = layout.row() row.operator('wm.textop' , text='Add Text' , icon='OUTLINER_OB_FONT' ) class WM_OT_textOp (bpy.types.Operator): bl_label = 'Text Tool Operator' bl_idname = 'wm.textop' text: bpy.props.StringProperty(name='Enter Text' , default='' ) scale: bpy.props.FloatVectorProperty(name='Scale' , default=(1 , 1 , 1 )) rotation: bpy.props.BoolProperty(name='Z up' , default=False ) center: bpy.props.BoolProperty(name='Center Origin' , default=False ) extrude: bpy.props.BoolProperty(name='Extrude' , default=False ) extrude_amount: bpy.props.FloatProperty(name='Extrude Amount' , default=0.06 ) def draw (self, context ): layout = self.layout layout.separator(factor=1 ) layout.label(text='Sample Text' ) layout.prop(self, 'text' ) layout.prop(self, 'scale' ) layout.separator(factor=2 ) box = layout.box() row = box.row() row.prop(self, 'rotation' ) if self.rotation == True : row.label(text='Orientation: Z UP' , icon='EMPTY_SINGLE_ARROW' ) else : row.label(text='Orientation: Default' , icon='ARROW_LEFTRIGHT' ) row = box.row() row.prop(self, 'center' ) if self.center == True : row.label(text='Alignment: Center' , icon='ALIGN_CENTER' ) else : row.label(text='Alignment: Default' , icon='ALIGN_LEFT' ) row = box.row() row.prop(self, 'extrude' ) if self.extrude == True : row.prop(self, 'extrude_amount' ) def execute (self, context ): t = self.text s = self.scale c = self.center e = self.extrude ea = self.extrude_amount r = self.rotation bpy.ops.object .text_add(enter_editmode=True , location=(0 , 0 , 0 )) bpy.ops.font.delete(type ='PREVIOUS_WORD' ) bpy.ops.font.text_insert(text=t) bpy.ops.object .editmode_toggle() if r == True : bpy.context.object .rotation_euler[0 ] = 1.5708 if e == True : bpy.context.object .data.extrude = ea if c == True : bpy.context.object .data.align_x = 'CENTER' bpy.context.object .data.align_y = 'CENTER' return {'FINISHED' } def invoke (self, context, event ): return context.window_manager.invoke_props_dialog(self)def register (): bpy.utils.register_class(OBJECT_PT_TextTool) bpy.utils.register_class(WM_OT_textOp)def unregister (): bpy.utils.unregister_class(OBJECT_PT_TextTool) bpy.utils.register_class(WM_OT_textOp)if __name__ == "__main__" : register()
Shortcut / Custom Keymap [learn python for beginners] 修改 popupdialogboxTemplate.py
,使其可以通过按下 SHIFT+F
打开 dialog box:
import bpyclass WM_OT_myOp (bpy.types.Operator): """Open the Add Cube Dialog Box""" bl_label = 'Add Cube Dialog Box' bl_idname = 'wm.myop' text: bpy.props.StringProperty(name='Enter Text' , default='' ) scale: bpy.props.FloatVectorProperty(name='Scale' , default=(1 , 1 , 1 )) def execute (self, context ): t = self.text s = self.scale bpy.ops.mesh.primitive_cube_add() obj = bpy.context.object obj.name = t obj.scale[0 ] = s[0 ] obj.scale[1 ] = s[1 ] obj.scale[2 ] = s[2 ] return {'FINISHED' } def invoke (self, context, event ): return context.window_manager.invoke_props_dialog(self) addon_keymaps = []def register (): bpy.utils.register_class(WM_OT_myOp) wm = bpy.context.window_manager kc = wm.keyconfigs.addon if kc: km = kc.keymaps.new(name='3D View' , space_type='VIEW_3D' ) kmi = km.keymap_items.new('wm.myop' , type ='F' , value='PRESS' , shift=True ) addon_keymaps.append((km, kmi)) def unregister (): for km, kmi in addon_keymaps: km.keymap_items.remove(kmi) addon_keymaps.clear() bpy.utils.unregister_class(WM_OT_myOp) if __name__ == '__main__' : register()
在 3D View
中按下 SHIFT+F
就可以打开 dialogbox: